今天繼續探討 變數和 null-safety
這裡宣告了 name 是可 null 的變數, 如果要對此變數做操作 Kotlin 是不允許的
從錯誤提示可以看到可以使用 ?. 或 !!. 來完成操作
?. 會判斷變數是否為 null, 若是 null 就不會執行 toUpperCase() 了
!!. 則會繼續執行, 可以看到結果會拋出 Exception
fun main() {
var name: String? = null
println(name?.toUpperCase()) // null
println(name!!.toUpperCase()) // throw kotlin.KotlinNullPointerException
}
結果:
null
Exception in thread "main" kotlin.KotlinNullPointerException
at day4.AppKt.main(App.kt:10)
at day4.AppKt.main(App.kt)
所以通常都是使用 ?. , !!. 只有用在很確定這個值不是 null 的時候
會這樣取名是因為 ?: 就像貓王的髮型一樣, 很有趣吧 XD
這個運算子可以直接幫我檢查是否為 null, 並給一個預設值
// Elvis operator
val name2: String = name ?: "default name" // default name
println(name2)
是不是很方便? 在 Java 裡面就可能還要用三元運算式(Ternary operator)寫成這樣...寫久了其時蠻囉唆的
String name2 = (name != null) ? name : "default name";
順帶一題, Kotlin 沒有三元運算式
真的要類似這樣的方式, 就用 if else 吧
在 Java 的時候, 有所謂的 8 大基礎類型和最常用的 String
Java 8 大基礎類型
和相對應的 Wrapper Class
而在 Kotlin 內比較簡潔, 就是直接以下的 9 種基礎類型, 沒有在分 class 了
val name4 = "tim"
val name5 = "TIM"
println(name4.toUpperCase() == name5) // true, 內容相等
println(name4.toUpperCase() === name5) // false, 物件指向的記憶體位置不同
由此可以看到, 有別於以往 Java 還需要用 .equals() 去比較字串內容, Kotlin 其實採用了最直覺的比較方式, 因為一般來說常比較的其實都是變數內的值, 而不是物件的記憶體位置
以下是 Kotlin 與其他語言 equlity 比較的圖表
Column 1 | Kotlin | Java |
---|---|---|
物件內的值(value) | == | .equals() |
物件的記憶體位置(memory address) | === | == |
順帶一提, 因為在 Java 中內容一樣的字串創立會共用 string pool, 在 Kotlin 裡面也一樣, 所以以下的例子, 無論內容和記憶體位置都是相同的!
val name6 = "tim"
val name7 = "tim"
println(name6 == name7) // true, 內容相等
println(name6 === name7) // true, 物件指向的記憶體位置相同, 在 java 中, 內容一樣的字串創立會共用 string pool
if else 在 Kotlin 中, 其實跟其他語言差不多, 讓我們看一下範例
val address: String? = null
if (address != null) {
println("address is $address") // address is null
} else {
println("address is null")
}
但官方的範例有著更簡潔的寫法, 如此可以一句判斷後把結果賦予到 max 變數上
(這跟 Goolgle Java code style 不大一樣, 但在 Kotlin 的 Goolgle 官方 style 確是可以這樣來寫的, 可以參考這裡 https://developer.android.com/kotlin/style-guide#expressions)
// as expression
val num1 = 10
val num2 = 12
val max = if (num1 > num2) num1 else num2
也可以寫成這樣, 這樣的寫法只要在 block 內最後一個的變數不用寫 return 就可以變成回傳值!
val max2 = if (num1 > num2) {
print("max is num1")
num1
} else {
print("max is num2")
num2
}
Kotlin 的 when 相當好用也很清楚明瞭, 這裡我建立了一個 fun, 參數型態設為 Any, 這樣任何型態都可以傳入, 方便測試
這裡使用了幾個狀況
這個例子來說, 整個 when 的判斷後的結果會以 → 對應到結果的字串, 最後再賦予給 result 變數
fun whenFun(num: Any) {
val result = when (num) {
0 -> "it's zero"
in 1..99 -> "it's between 1 to 99" // 使用 range 來比對(1~99)
100, 101 -> "it's 100 or 101" // 100 或 101
in listOf("a", "b", "c") -> "in some list" // 確認 num 是否在這 list 裡面
!in setOf("a", "b", "c") -> "not in this set" // 確認 num 是否 不在這 set 裡面
is Int -> "it's Integer" // 型態是否是 Int
is String -> "it's String" // 型態是否是 String
is BigDecimal -> "it's BigDecimal" // 型態是否是 BigDecimal
!is Double -> "it's not Double" // 型態不是 Double
else -> "not match" // 對應不到時預設值
}
println(result)
}
呼叫後可以得到以下結果
fun main() {
whenFun(98) // it's between 1 to 99
whenFun("c") // in some list
whenFun(1000) // it's Integer
whenFun(BigDecimal.ONE) //it's BigDecimal
}
在上面的 when 的例子也可以發現到, 不用 break 就可以完成耶!
以前寫 Java 的話都要 break; 不然會形成一個災難啊...
switch(a) {
case 1:
// ..
break;
case 2:
// ..
break;
case 3:
// ..
break;
}
普通的 for 語法像是這樣
// for example
val numList = listOf(1, 2, 3, 4, 5, 6)
for (num in numList) { // for in
println(num)
}
要寫的 lambda 一點的風格可以使用 forEach
只有一個參數時, 在 lambda 裡面可以直接使用 it 此參數
// forEach
numList.forEach { num -> println(num) }
numList.forEach { println(it) }
while 跟其他語言相同, do while 差別在於 do 裡面的程式碼會先執行, 在做 while
// while
val end = 5
var i = 0
while (i < end) {
println(i)
i++
}
// do while
var j = 0
do {
j++
println("do while $j")
} while (j < end)
repeat 也是 lambda 的寫法, 語法很簡單, 下面這樣就是重複 0~4
// repeat
repeat(5) { println(it) }
以上就是今天的內容!!我們明天見!
今日練習的程式在這: 請點我